/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator.core.rtgen.datagenerator;


import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bff.designtime.generator.core.rtgen.datagenerator.methodgenerator.FSDataConstructorGenerator;
import com.inspur.edp.bff.designtime.generator.core.rtgen.typeinfo.FSDataClassTypeInfo;
import com.inspur.edp.caf.generator.baseInfo.AnnotationInfo;
import com.inspur.edp.caf.generator.baseInfo.AnnotationType;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.item.ClassGeneratorContext;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.cef.gencommon.MediateType;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.EntityDataImplGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.EntityGeneratorContext;
import com.inspur.edp.cef.generator.coreGenerator.base.serializer.dataser.serializer.EntityDataSerGenContext;
import com.inspur.edp.cef.generator.repository.common.IntermediateType;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import lombok.var;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.TypeLiteral;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;

public class FSDataClassGenerator extends EntityDataImplGenerator {
    private FSDataGeneratorContext fsDataGenContext;
    private GspViewObject object;
    private boolean isRoot;
    private GspBizEntityObject refObject;
    private GspBusinessEntity refBe;

    public FSDataClassGenerator(FSDataGeneratorContext parContext, GspViewObject object, MediateType targetInterfaceType) {
        super(parContext, object, targetInterfaceType);
        fsDataGenContext = parContext;
        this.object = object;
        isRoot = object.isRootNode();

        refBe = parContext.getFsGenContext().getVmGenContext().getRefBizEntity();
        if (!object.isVirtual())
            refObject = (GspBizEntityObject) refBe.findObjectById(object.getMapping().getTargetObjId());
        InitObjectMapping();
    }

    private FSDataClassGenContext getBffDataClassGenContext() {
        return (FSDataClassGenContext) (super.getContext());
    }

    @Override
    protected EntityDataImplGenerator getDataChildsGenerator(EntityGeneratorContext entityGeneratorContext, IGspCommonObject childObj) {
        return new FSDataClassGenerator((FSDataGeneratorContext) entityGeneratorContext, (GspViewObject) childObj, fsDataGenContext.getProjContext().getCefGenContext().getEntityGenContext().getNodeTypes()
                .get(childObj.getCode()));
    }

    @Override
    protected ClassGeneratorContext createClassInfoContext() {
        return new FSDataClassGenContext(fsDataGenContext);
    }

    public final String GetFullName() {
        return GetNameSpace() + getName();//"{GetNameSpace()}.{GetName()}";
    }

    protected String GetNameSpace() {
        return fsDataGenContext.getFsGenContext().getConfig().getDefaultNamespace();
    }

    private void InitObjectMapping() {
        for (IGspCommonObject childObj : object.getContainChildObjects()) {
            GspViewObject childVoObj = (GspViewObject) childObj;
            if (childVoObj.isVirtual())
                continue;
            IGspCommonObject refObj;
            if (!childVoObj.getMapping().getTargetMetadataId().equals(refBe.getID())) {
                refBe = (GspBusinessEntity) fsDataGenContext.getFsGenContext().getVmGenContext().getMetadata("", childVoObj.getMapping().getTargetMetadataId()).getContent();
            }

            refObj = refBe.findObjectById(childVoObj.getMapping().getTargetObjId());
            fsDataGenContext.getFsGenContext().getFsIntermediateTypeInfo().getFSDataInfo().getVmBEObjectMappingDict().put(childObj.getCode(), refObj.getCode());
        }
    }

    @Override
    protected ArrayList<ClassMethodGenerator> createConstructorGenerators() {
        return new ArrayList<>(Arrays.asList(new ClassMethodGenerator[]{new FSDataConstructorGenerator(getName())}));
    }

    private FSDataClassTypeInfo getFsDataInfo() {
        return getBffDataClassGenContext().getFsDataGenContext().getFsGenContext().getFsIntermediateTypeInfo().getFSDataInfo();
    }

    @Override
    protected void afterGenerate() {
        super.afterGenerate();
        MediateType typeInfo = new MediateType(GetNameSpace(),getName());
        if (isRoot) {
            getFsDataInfo().setMainCode(object.getCode());
            if (!object.isVirtual())
                getFsDataInfo().getVmBEObjectMappingDict().put(object.getCode(), refObject.getCode());
            getFsDataInfo().setMainDataType(typeInfo);
        } else {
            getFsDataInfo().getChildObjDataTypes().put(object.getCode(), typeInfo);
        }
    }

    @Override
    protected ArrayList<AnnotationInfo> getAttributeList() {
        var annoInfos = super.getAttributeList();
        if (annoInfos == null)
            annoInfos = new ArrayList<>();

        //region JsonSerialize
        AnnotationInfo annotationInfo = new AnnotationInfo();
        TypeInfo typeInfo = new TypeInfo(JsonSerialize.class);
        annotationInfo.setTypeInfo(typeInfo);
        annotationInfo.setAnnotationType(AnnotationType.Normal);
        HashMap<String, Expression> params = new HashMap<>();

        String convertName = fsDataGenContext.getFsGenContext().getCommonModel().getCode() + "EntitySerConvertor";
            //= "com.inspur.edp.bff.spi.BfEntitySerConvertor";
//        if (isRoot)
//            convertName = fsDataGenContext.getFsGenContext().getMgrContext().getDataSerContext().getMainObjectType().getClassName();
//        else
//            convertName = ((EntityDataSerGenContext) fsDataGenContext.getFsGenContext().getMgrContext().getDataSerContext()).getChildTypes().get(NodeCode).getClassName();
        TypeLiteral type = ast.newTypeLiteral();
        type.setType(ast.newSimpleType(ast.newSimpleName(convertName)));
        params.put("using", type);
        annotationInfo.setParams(params);
        annoInfos.add(annotationInfo);
        //endregion

        //region JsonDeserialize
//        var annotation = new AnnotationInfo();
//        annotation.setTypeInfo(new TypeInfo(JsonDeserialize.class));
//        String desConvertorName;
//            //= "com.inspur.edp.bff.spi.BfEntityDeserConvertor";
//        if (isRoot)
//            desConvertorName = fsDataGenContext.getFsGenContext().getMgrContext().getDataSerContext().getDeserMainObjType().getClassName();
//        else
//            desConvertorName = ((EntityDataSerGenContext) fsDataGenContext.getFsGenContext().getMgrContext().getDataSerContext()).getDeserChildTypes().get(NodeCode).getClassName();
//
//        var desType = ast.newTypeLiteral();
//        desType.setType(ast.newSimpleType(ast.newSimpleName(desConvertorName)));
//        annotation.getParams().put("using", desType);
//        annoInfos.add(annotation);
        //endregion

        return annoInfos;
    }
}
